﻿// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright (c) Microsoft Corporation. All rights reserved

using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using System.Text;
using NETWORKLIST;

namespace Microsoft.Samples.Windows.NLM.NetworkListSample
{
    class AppNetworkListUser : INetworkListManagerEvents, INetworkEvents, IDisposable
    {
        private int m_nlmcookie = 0;
        private int m_netcookie = 0;
        private IConnectionPoint m_nlmicp;
        private IConnectionPoint m_neticp;
        private INetworkListManager m_nlm;

        public INetworkListManager NLM
        {
            get
            {
                return m_nlm;
            }
        }
        AppNetworkListUser()
        {
            m_nlm = new NetworkListManager();            
        }
       
        #region Implement IDisposable
        //Implement IDisposable to free up unmanaged resources and unsubscribe event sink.
       public void Dispose() 
       {
          Dispose(true);
          GC.SuppressFinalize(this); 
       }

       protected virtual void Dispose(bool disposing) 
       {
          if (disposing) 
          {
              UnAdviseforNetworklistManagerEvent();
              UnAdviseforNetworkEvent();
              Marshal.FinalReleaseComObject(m_nlm);
          }
       }

        // Use C# destructor syntax for finalization code.
        ~AppNetworkListUser()
        {
          Dispose (false);
        }
        #endregion

        #region Implement INetworklistManagerEvent
        // invoked for INetworklistManagerEvent to process machine level connectivity change
        public void ConnectivityChanged(NLM_CONNECTIVITY newConnectivity)
        {
            Console.WriteLine("");
            Console.WriteLine("---------------------------------------------------------------------------");
            Console.WriteLine("NetworkList just informed the connectivity change. The new connectivity is:");
            Console.WriteLine("The machine is " + GetNLMConnectivity(newConnectivity));
            Console.WriteLine("---------------------------------------------------------------------------");
        }
        #endregion

        #region Implement INetworkEvent
        //Invoked when a new network is added in the machine.
        public void NetworkAdded(Guid networkId)
        {
            Console.WriteLine("");
            Console.WriteLine("---------------------------------------------------------------------------");
            Console.WriteLine("New event for network added:");
            
            Console.WriteLine("The network " + m_nlm.GetNetwork(networkId).GetName() + " with ID " + networkId.ToString() + " has been added");
            Console.WriteLine("---------------------------------------------------------------------------");
        }

       //Invoked when the connectivity of a network is changed.
       public void NetworkConnectivityChanged(Guid networkId, NLM_CONNECTIVITY newConnectivity)                    
        {
            Console.WriteLine("");
            Console.WriteLine("---------------------------------------------------------------------------");
            Console.WriteLine("New event for network Connectivity changed :");
            Console.WriteLine("The network " + m_nlm.GetNetwork(networkId).GetName() + " with ID " + networkId.ToString() + "   " + GetNLMConnectivity(newConnectivity));
            Console.WriteLine("---------------------------------------------------------------------------");
        }

       //Invoked when a network is deleted in the machine.
        public void NetworkDeleted(Guid networkId)
        {
            Console.WriteLine("");
            Console.WriteLine("---------------------------------------------------------------------------");
            Console.WriteLine("New event for network deleted: ");
            Console.WriteLine("The network " + m_nlm.GetNetwork(networkId).GetName() + " with ID " + networkId.ToString() + " has been deleted");
            Console.WriteLine("---------------------------------------------------------------------------");
        }

        //Invoked when the property of a network is changed
        public void NetworkPropertyChanged(Guid networkId, NLM_NETWORK_PROPERTY_CHANGE Flags)
        {
            Console.WriteLine("");
            Console.WriteLine("---------------------------------------------------------------------------");
            Console.WriteLine("New event for network property changed:");
            StringBuilder changeDescription = new StringBuilder();
            if (((int)Flags & (int)NLM_NETWORK_PROPERTY_CHANGE.NLM_NETWORK_PROPERTY_CHANGE_NAME) != 0)
            {
                changeDescription.Append(" network name has changed to " + m_nlm.GetNetwork(networkId).GetName() + "\n");
            }
            if (((int)Flags & (int)NLM_NETWORK_PROPERTY_CHANGE.NLM_NETWORK_PROPERTY_CHANGE_DESCRIPTION) != 0)
            {
                changeDescription.Append(" network decription has changed to " + m_nlm.GetNetwork(networkId).GetDescription() + "\n");
            }
            if (((int)Flags & (int)NLM_NETWORK_PROPERTY_CHANGE.NLM_NETWORK_PROPERTY_CHANGE_CATEGORY_VALUE) != 0)
            {
                changeDescription.Append(" network category has changed\n");
            }
            if (((int)Flags & (int)NLM_NETWORK_PROPERTY_CHANGE.NLM_NETWORK_PROPERTY_CHANGE_CONNECTION) != 0)
            {
                changeDescription.Append(" network connections within the network has changed\n");
            }

            Console.WriteLine("The network with ID " + networkId.ToString() + " has following changes");
            Console.WriteLine(changeDescription.ToString());
            Console.WriteLine("---------------------------------------------------------------------------");
        }
       #endregion

        #region Implement Event subscribe and unsubscribe
        //Subscribe for INetworlistManagerEvent
        public void AdviseforNetworklistManagerEvent()
        {
            Console.WriteLine("Subscribing the INetworkListManagerEvents");
            IConnectionPointContainer icpc = (IConnectionPointContainer)m_nlm;
            //similar event subscription can be used for INetworkConnectionEvents
            Guid tempGuid = typeof(INetworkListManagerEvents).GUID;
            icpc.FindConnectionPoint(ref tempGuid , out m_nlmicp);
            m_nlmicp.Advise(this, out m_nlmcookie);
        }

        //Unsubscribe for INetworlistManagerEvent. No more notification afterwards.
        public void UnAdviseforNetworklistManagerEvent()
        {
            if (m_nlmcookie != 0)
            {
                Console.WriteLine("Unsubscribing the INetworkListManagerEvents");
                m_nlmicp.Unadvise(m_nlmcookie);
            }
            m_nlmcookie = 0;
        }       

        //Subscribe for INetworkEvent
        public void AdviseforNetworkEvent()
        {
            Console.WriteLine("Subscribing the INetworkEvents");
            IConnectionPointContainer icpc = (IConnectionPointContainer)m_nlm;
            //similar event subscription can be used forINetworkConnectionEvents
            Guid tempGuid = typeof(INetworkEvents).GUID;
            icpc.FindConnectionPoint(ref tempGuid, out m_neticp);
            m_neticp.Advise(this, out m_netcookie);
        }

        //Unsubscribe for INetworkEvent. No more notification afterwards.
        public void UnAdviseforNetworkEvent()
        {
            if (m_netcookie != 0)
            {
                Console.WriteLine("Unsubscribing the INetworkEvents");
                m_neticp.Unadvise(m_netcookie);
            }
            m_netcookie = 0;
        }
        #endregion

        //Entry for the application
        static void Main()
        {
            AppNetworkListUser nlmUser = new AppNetworkListUser();
            Console.WriteLine("Is the machine connected to internet? " + nlmUser.NLM.IsConnectedToInternet.ToString());            
            //List the connected networks. There are many other APIs can be called to get network information.
            Console.WriteLine("********************List of all networks********************");
            IEnumNetworks Networks = nlmUser.NLM.GetNetworks(NLM_ENUM_NETWORK.NLM_ENUM_NETWORK_ALL);
            foreach (INetwork item in Networks)
            {
                nlmUser.PrintNetworkDetails(item);
            }
            Console.WriteLine("********************End List of all networks********************");

            //Subscribe for NetworListManager Event
            nlmUser.AdviseforNetworklistManagerEvent();
            //Subscribe for Network Event
            nlmUser.AdviseforNetworkEvent();

            Console.WriteLine("Press any key and enter to finish the program");
            Console.ReadLine();
            //tell the nlmUser to unsubscribe event and release resources.
            nlmUser.Dispose();
        }

        //Print out the network details such as name, category, domaintype etc.
        public void PrintNetworkDetails(INetwork network)
        {
            Console.WriteLine("********************details of a network********************");
            Console.WriteLine("Network Name:" + network.GetName());
            Console.WriteLine("Network ID:" + network.GetNetworkId().ToString());
            Console.WriteLine("Network description:" + network.GetDescription());
            if(network.GetDomainType() == NLM_DOMAIN_TYPE.NLM_DOMAIN_TYPE_DOMAIN_AUTHENTICATED)
            {
                Console.WriteLine("Network is domain authenticated");
            }
            
            
            NLM_NETWORK_CATEGORY Category = network.GetCategory();
            if (Category == NLM_NETWORK_CATEGORY.NLM_NETWORK_CATEGORY_PUBLIC)
            {
                Console.WriteLine("Network category is public network");
            }
            else if ((Category == NLM_NETWORK_CATEGORY.NLM_NETWORK_CATEGORY_PRIVATE))
            {
                Console.WriteLine("Network category is private network");
            }
            else
            {
                Console.WriteLine("Network category is domain network");
            }
            
            //list the connections within this network.
            IEnumNetworkConnections connections = network.GetNetworkConnections();           
            foreach(INetworkConnection connection in connections)
            {
                PrintNetworkConnectionDetails(connection);
            }
            Console.WriteLine("********************end details of a network********************");
            Console.WriteLine();
        }

        //Print the details of a network conneciton, such as adapter id, connectivity .
        public void PrintNetworkConnectionDetails(INetworkConnection netconnection)
        {
            Console.WriteLine("    --------------details of a network connection-----------------------");
            Console.WriteLine("    The unique id for this network connection is: " + netconnection.GetConnectionId().ToString());
            Console.WriteLine("    Network adapter GUID for this connection is: " + netconnection.GetAdapterId().ToString());
            if(netconnection.IsConnectedToInternet)
            {
                Console.WriteLine("    This network connection is connected to Internet");    
            }
            else if (netconnection.IsConnected)
            {
                Console.WriteLine("    This network connection is connected to local network");    
            }
            else
            {
                Console.WriteLine("    This network connection is not connected to network");    
            }

            // you can get connectivity for each connection too. 
            Console.WriteLine("    The connectivity of this layer 2 connection is: " + GetNLMConnectivity(netconnection.GetConnectivity()));
            Console.WriteLine("   ------------------end details a network connection-----------------------");
        }

        //Translate NLM_CONNECTIVITY data into a String
        public String GetNLMConnectivity(NLM_CONNECTIVITY connectivity)
        {
            if (connectivity == NLM_CONNECTIVITY.NLM_CONNECTIVITY_DISCONNECTED)
            {
                return "disconnected from Network";
            }
            else
            {
                //changes for local and not to internet yet
                if ((((int)connectivity & (int)NLM_CONNECTIVITY.NLM_CONNECTIVITY_IPV4_INTERNET) == 0)
                    && (((int)connectivity & (int)NLM_CONNECTIVITY.NLM_CONNECTIVITY_IPV6_INTERNET) == 0))
                {
                    return "not connected to internet yet";
                }
                else
                {
                    StringBuilder temp = new StringBuilder();
                    if (((int)connectivity & (int)NLM_CONNECTIVITY.NLM_CONNECTIVITY_IPV4_INTERNET) != 0)
                    {
                        temp.Append( "connected to internet with IPv4 capability ");
                    }
                    if (((int)connectivity & (int)NLM_CONNECTIVITY.NLM_CONNECTIVITY_IPV6_INTERNET) != 0)
                    {
                        temp.Append("  connected to internet with IPv6 capability ");
                    }
                    return temp.ToString();
                }
            }
        }
    }
}
